#include "qmemerymanager.h"

#include "qvaluexml.h"

#include <QVariant>
#include <QFile>

#include <QXmlStreamReader>
#include <QXmlStreamWriter>

using namespace SHAREDLIB;

QMemeryManager::QMemeryManager(QObject *parent) :
    QObject(parent)
{
}

QMemeryManager::~QMemeryManager()
{
    clear();
}

void QMemeryManager::addData(QObject *obj)
{
    if(obj==NULL || m_datas.contains(obj))
    {
        return;
    }
    QString name=obj->property("name").toString();
    QString group=obj->property("group").toString();
    if(m_groupToObject.value(group).value(name)!=NULL)
    {
        return;
    }
    QMap<QString,QObject*>  g=m_groupToObject.value(group);
    g.insert(name,obj);
    m_groupToObject.insert(group,g);
    m_datas.append(obj);
    emit addDataSignal(obj);
}

void QMemeryManager::removeData(const QString &group, const QString &name)
{
    QObject *obj=m_groupToObject.value(group).value(name);
    if(obj!=NULL)
    {
        QMap<QString,QObject*>  g=m_groupToObject.value(group);
        g.remove(name);
        if(g.size()==0)
        {
            m_groupToObject.remove(group);
        }
        else
        {
            m_groupToObject.insert(group,g);
        }
        m_datas.removeAll(obj);
        emit removeDataSignal(obj);
        delete obj;
    }
}

void QMemeryManager::removeDatas(const QList<QObject *> &datas)
{
    QString name,group;
    QMap<QString,QObject*>  g;
    bool bSignal=false;
    foreach(QObject* obj,datas)
    {
        if(m_datas.contains(obj))
        {
            name=obj->property("name").toString();
            group=obj->property("group").toString();
            g=m_groupToObject.value(group);
            g.remove(name);
            if(g.size()==0)
            {
                m_groupToObject.remove(group);
            }
            else
            {
                m_groupToObject.insert(group,g);
            }
            m_datas.removeAll(obj);
            delete obj;
            bSignal=true;
        }
    }
    if(bSignal)
    {
        emit refresh();
    }
}

QObject* QMemeryManager::getData(const QString &group, const QString &name)
{
    return m_groupToObject.value(group).value(name);
}

QObject* QMemeryManager::getData(int index)
{
    if(index>=0 || index<m_datas.size())
    {
        return m_datas.at(index);
    }
    else
    {
        return NULL;
    }
}

int QMemeryManager::dataIndex(QObject *obj)
{
    return m_datas.indexOf(obj);
}

int QMemeryManager::dataCount()
{
    return m_datas.size();
}

void QMemeryManager::load(const QString &projectPath)
{
    QFile f(projectPath+"/values.xml");
    if(!f.open(QFile::ReadOnly))
    {
        return;
    }

    QXmlStreamReader r(&f);

    while(!r.atEnd())
    {
        if(r.readNext()==QXmlStreamReader::StartElement)
        {
            if(r.name().toString()=="Value")
            {
                readData(&r);
                if(r.hasError())
                {
                    break;
                }
            }
        }
    }
    if(r.hasError())
    {
        qDebug((r.errorString()).toLocal8Bit());
        clear();
    }
    else
    {
        emit refresh();
    }
}

void QMemeryManager::readData(QXmlStreamReader *r)
{
    QObject* obj=new QObject;
    QString str;
    foreach(const QXmlStreamAttribute &attribute,r->attributes())
    {
        str=attribute.name().toString();
        if(str=="Name")
        {
            obj->setProperty("name",attribute.value().toString());
        }
        else if(str=="Hold")
        {
            obj->setProperty("hold",attribute.value().toString());
        }
        else if(str=="Save_Period")
        {
            obj->setProperty("save",attribute.value().toString());
        }
        else if(str=="Information")
        {
            obj->setProperty("information",attribute.value().toString());
        }
        else if(str=="Group")
        {
            obj->setProperty("group",attribute.value().toString());
        }
    }
    if(obj->property("name").toString()==""
            || obj->property("group").toString()=="")
    {
        delete obj;
        r->raiseError("Data parse error!");
        return;
    }

    QString type;
    for(bool finished=false;!finished && !r->hasError();)
    {
        switch(r->readNext())
        {
        case QXmlStreamReader::StartElement:
            type=r->name().toString();
            if(type!="")
            {
                XMLValue *value=XMLValueFactory::create(type);
                if(value!=NULL)
                {
                    value->read(r);
                    obj->setProperty("type",type);
                    obj->setProperty("data",value->value());
                    addData(obj);
                    delete value;
                }
                else
                {
                    delete obj;
                    r->raiseError("Data parse error!");
                    return;
                }
            }
             break;
        case QXmlStreamReader::EndElement:
            finished=true;
            break;
        case QXmlStreamReader::Characters:
            break;
        default:
            break;
        }
    }
}

void QMemeryManager::save(const QString &projectPath)
{
    QFile f(projectPath+"/values.xml");
    if(!f.open(QFile::WriteOnly))
    {
        return;
    }
    f.resize(0);
    QXmlStreamWriter w(&f);
    w.setAutoFormatting(true);
    w.writeStartDocument();

    w.writeStartElement("Values");

    foreach(QObject* obj,m_datas)
    {
        XMLValue *value=XMLValueFactory::create(obj->property("type").toString());
        if(value==NULL)
        {
            continue;
        }
        value->setValue(obj->property("data"));
        w.writeStartElement("Value");

        w.writeAttribute("Name",obj->property("name").toString());
        w.writeAttribute("Group",obj->property("group").toString());
        w.writeAttribute("Hold",obj->property("hold").toString());
        w.writeAttribute("Save_Period",obj->property("save").toString());
        w.writeAttribute("Information",obj->property("information").toString());

        value->write(&w);
        delete value;

        w.writeEndElement();
    }

    w.writeEndElement();

    w.writeEndDocument();
}

void QMemeryManager::clear()
{
    qDeleteAll(m_datas);
    m_datas.clear();
    m_groupToObject.clear();
    emit refresh();
}

void QMemeryManager::refreshData()
{
    emit refresh();
}

QStringList QMemeryManager::namesList(const QString &group)
{
    return m_groupToObject.value(group).keys();
}

QStringList QMemeryManager::groups()
{
    return m_groupToObject.keys();
}

void QMemeryManager::changedName(const QString &newName, QObject *obj)
{
    QMap<QString,QObject*> g=m_groupToObject.value(obj->property("group").toString());
    g.remove(obj->property("name").toString());
    g.insert(newName,obj);
    obj->setProperty("name",newName);
}

void QMemeryManager::changedData(const QVariant &data, QObject *obj)
{
    QVariant d=obj->property("data");
    if(d!=data)
    {
        obj->setProperty("data",data);
        emit dataChanged(obj);
    }
}
